package com.fish.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fish.common.constant.JwtConstant;
import com.fish.common.util.JwtUtil;
import com.fish.common.util.RedisUtil;
import com.fish.dao.mapper.RefreshTokenMapper;
import com.fish.dao.mapper.TokenBlacklistMapper;
import com.fish.model.entity.RefreshToken;
import com.fish.model.entity.TokenBlacklist;
import com.fish.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * Token服务实现类
 */
@Slf4j
@Service
public class TokenServiceImpl implements TokenService {
    
    @Autowired
    private RefreshTokenMapper refreshTokenMapper;
    
    @Autowired
    private TokenBlacklistMapper tokenBlacklistMapper;
    
    @Autowired
    private RedisUtil redisUtil;
    
    private static final String TOKEN_BLACKLIST_KEY = "token:blacklist:";
    private static final long BLACKLIST_CACHE_SECONDS = 24 * 60 * 60; // 缓存24小时
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRefreshToken(Long userId, String refreshToken) {
        // 先删除用户已有的Refresh Token
        LambdaQueryWrapper<RefreshToken> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(RefreshToken::getUserId, userId);
        refreshTokenMapper.delete(deleteWrapper);
        
        // 保存新的Refresh Token
        RefreshToken token = new RefreshToken();
        token.setUserId(userId);
        token.setToken(refreshToken);
        token.setExpireTime(LocalDateTime.now().plusDays(90)); // 90天后过期
        token.setCreateTime(LocalDateTime.now());
        
        refreshTokenMapper.insert(token);
        log.info("保存Refresh Token成功，userId: {}", userId);
    }
    
    @Override
    public boolean validateRefreshToken(String refreshToken) {
        // 1. 先验证JWT本身是否有效
        if (!JwtUtil.validateToken(refreshToken)) {
            return false;
        }
        
        // 2. 验证是否为Refresh Token
        if (!JwtUtil.isRefreshToken(refreshToken)) {
            return false;
        }
        
        // 3. 检查数据库中是否存在该Token
        LambdaQueryWrapper<RefreshToken> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RefreshToken::getToken, refreshToken);
        wrapper.gt(RefreshToken::getExpireTime, LocalDateTime.now());
        RefreshToken token = refreshTokenMapper.selectOne(wrapper);
        
        return token != null;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRefreshToken(Long userId) {
        LambdaQueryWrapper<RefreshToken> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RefreshToken::getUserId, userId);
        refreshTokenMapper.delete(wrapper);
        log.info("删除Refresh Token成功，userId: {}", userId);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addToBlacklist(String token, Long userId, String reason) {
        // 1. 保存到数据库
        TokenBlacklist blacklist = new TokenBlacklist();
        blacklist.setToken(token);
        blacklist.setUserId(userId);
        blacklist.setReason(reason);
        blacklist.setExpireTime(LocalDateTime.now().plusDays(1)); // 黑名单保留1天
        blacklist.setCreateTime(LocalDateTime.now());
        
        tokenBlacklistMapper.insert(blacklist);
        
        // 2. 缓存到Redis（加快查询速度）
        String cacheKey = TOKEN_BLACKLIST_KEY + token;
        redisUtil.set(cacheKey, true, BLACKLIST_CACHE_SECONDS);
        
        log.info("Token已加入黑名单，userId: {}, reason: {}", userId, reason);
    }
    
    @Override
    public boolean isInBlacklist(String token) {
        // 1. 先从Redis缓存查询
        String cacheKey = TOKEN_BLACKLIST_KEY + token;
        Object cached = redisUtil.get(cacheKey);
        if (cached != null) {
            return true;
        }
        
        // 2. 缓存未命中，查询数据库
        LambdaQueryWrapper<TokenBlacklist> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TokenBlacklist::getToken, token);
        wrapper.gt(TokenBlacklist::getExpireTime, LocalDateTime.now());
        TokenBlacklist blacklist = tokenBlacklistMapper.selectOne(wrapper);
        
        if (blacklist != null) {
            // 更新缓存
            redisUtil.set(cacheKey, true, BLACKLIST_CACHE_SECONDS);
            return true;
        }
        
        return false;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cleanExpiredTokens() {
        // 清理过期的Refresh Token
        LambdaQueryWrapper<RefreshToken> refreshWrapper = new LambdaQueryWrapper<>();
        refreshWrapper.lt(RefreshToken::getExpireTime, LocalDateTime.now());
        int refreshCount = refreshTokenMapper.delete(refreshWrapper);
        
        // 清理过期的黑名单记录
        LambdaQueryWrapper<TokenBlacklist> blacklistWrapper = new LambdaQueryWrapper<>();
        blacklistWrapper.lt(TokenBlacklist::getExpireTime, LocalDateTime.now());
        int blacklistCount = tokenBlacklistMapper.delete(blacklistWrapper);
        
        log.info("清理过期Token完成，Refresh Token: {}, 黑名单: {}", refreshCount, blacklistCount);
    }
}